package com.movisol.c2dm.receivers;

import java.io.IOException;

import android.app.AlarmManager;
import android.app.IntentService;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.PowerManager;
import android.util.Log;

import com.movisol.c2dm.controllers.C2DMController;
import com.movisol.c2dm.helpers.C2DMHelper;
  
/** 
 * Base class for C2D message receiver. Includes constants for the strings used 
 * in the protocol. 
 */  
public abstract class C2DMBaseReceiver extends IntentService {  
    private static final String C2DM_RETRY = "com.google.android.c2dm.intent.RETRY";  
  
    public static final String REGISTRATION_CALLBACK_INTENT = "com.google.android.c2dm.intent.REGISTRATION";  
    private static final String C2DM_INTENT = "com.google.android.c2dm.intent.RECEIVE";  
  
    // Logging tag  
    private static final String TAG = "C2DM";  
  
    // Extras in the registration callback intents.  
    public static final String EXTRA_UNREGISTERED = "unregistered";  
  
    public static final String EXTRA_ERROR = "error";  
  
    public static final String EXTRA_REGISTRATION_ID = "registration_id";  
  
    public static final String ERR_SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";  
    public static final String ERR_ACCOUNT_MISSING = "ACCOUNT_MISSING";  
    public static final String ERR_AUTHENTICATION_FAILED = "AUTHENTICATION_FAILED";  
    public static final String ERR_TOO_MANY_REGISTRATIONS = "TOO_MANY_REGISTRATIONS";  
    public static final String ERR_INVALID_PARAMETERS = "INVALID_PARAMETERS";  
    public static final String ERR_INVALID_SENDER = "INVALID_SENDER";  
    public static final String ERR_PHONE_REGISTRATION_ERROR = "PHONE_REGISTRATION_ERROR";  
  
    // wakelock  
    private static final String WAKELOCK_KEY = "C2DM_LIB";  
  
    private static PowerManager.WakeLock mWakeLock;  
    private final String senderId;
    private Handler handler = new Handler();
    private C2DMController c2dm = C2DMController.getInstance();
  
    /** 
     * The C2DMReceiver class must create a no-arg constructor and pass the 
     * sender id to be used for registration. 
     */  
    public C2DMBaseReceiver(String senderId) {  
        // senderId is used as base name for threads, etc.  
        super(senderId);  
        this.senderId = senderId;  
    }  
  
    /** 
     * Called when a cloud message has been received. 
     */  
    protected abstract void onMessage(Context context, Intent intent);  
  
    /** 
     * Called on registration error. Override to provide better error messages. 
     *  
     * This is called in the context of a Service - no dialog or UI. 
     */  
    public abstract void onError(Context context, String errorId);  
  
    /** 
     * Called when a registration token has been received. 
     */  
    public void onRegistered(Context context, String registrationId)  
            throws IOException {  
        // registrationId will also be saved  
    }  
  
    /** 
     * Called when the device has been unregistered. 
     */  
    public void onUnregistered(Context context) {  
    }  
  
    @Override  
    public final void onHandleIntent(Intent intent) {  
        try {  
            Context context = getApplicationContext();  
            if (intent.getAction().equals(REGISTRATION_CALLBACK_INTENT)) {  
                handleRegistration(context, intent);  
            } else if (intent.getAction().equals(C2DM_INTENT)) {  
                onMessage(context, intent);  
            } else if (intent.getAction().equals(C2DM_RETRY)) {  
                C2DMHelper.registerPushNotifications(context, senderId);  
            }  
        } finally {  
            // Release the power lock, so phone can get back to sleep.  
            // The lock is reference counted by default, so multiple  
            // messages are ok.  
  
            // If the onMessage() needs to spawn a thread or do something else,  
            // it should use it's own lock.  
            mWakeLock.release();  
        }  
    }  
    
    public void firePushNotificationReceived(){
        handler.post(new FireNewPush());
    }
	
	private class FireNewPush implements Runnable{

	
		  public FireNewPush(){

		          }
		
		   public void run(){
			   	c2dm.firePushNotificationsListener();
		          }
	}
    
	
	public void fireRegistrationIdReceived(final String registrationId){
        handler.post(new Runnable() {
			
			@Override
			public void run() {
				c2dm.fireRegistrationListener(registrationId);
				
			}
		});
    }
	
	

  
    /** 
     * Called from the broadcast receiver. Will process the received intent, 
     * call handleMessage(), registered(), etc. in background threads, with a 
     * wake lock, while keeping the service alive. 
     */  
    static void runIntentInService(Context context, Intent intent) {  
        if (mWakeLock == null) {  
            // This is called from BroadcastReceiver, there is no init.  
            PowerManager pm = (PowerManager) context  
                    .getSystemService(Context.POWER_SERVICE);  
            mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,  
                    WAKELOCK_KEY);  
        }  
        mWakeLock.acquire();  
  
        // Use a naming convention, similar with how permissions and intents are  
        // used. Alternatives are introspection or an ugly use of statics.  
        String receiver = context.getPackageName().concat(".receivers.C2DMReceiver");  
        intent.setClassName(context, receiver);  
  
        context.startService(intent);  
  
    }  
  
    private void handleRegistration(final Context context, Intent intent) {  
        final String registrationId = intent  
                .getStringExtra(EXTRA_REGISTRATION_ID);  
        String error = intent.getStringExtra(EXTRA_ERROR);  
        String removed = intent.getStringExtra(EXTRA_UNREGISTERED);  
  
        if (Log.isLoggable(TAG, Log.DEBUG)) {  
            Log.d(TAG, "dmControl: registrationId = " + registrationId  
                    + ", error = " + error + ", removed = " + removed);  
        }  
  
        if (removed != null) {
            // Remember we are unregistered  
            C2DMHelper.clearRegistrationId(context);
            onUnregistered(context);
            return;
        } else if (error != null) {
            // we are not registered, can try again  
            C2DMHelper.clearRegistrationId(context);  
            // Registration failed  
            Log.e(TAG, "Registration error " + error);  
            onError(context, error);  
            if ("SERVICE_NOT_AVAILABLE".equals(error)) {
            	long backoffTimeMs = C2DMHelper.getBackoff(context);  
  
            	Log.d(TAG, "Scheduling registration retry, backoff = "  
                        + backoffTimeMs);  
                Intent retryIntent = new Intent(C2DM_RETRY);  
                PendingIntent retryPIntent = PendingIntent  
                        .getBroadcast(context, 0 /* requestCode */, retryIntent,  
                                0 /* flags */);  
  
                AlarmManager am = (AlarmManager) context  
                        .getSystemService(Context.ALARM_SERVICE);  
                am.set(AlarmManager.ELAPSED_REALTIME, backoffTimeMs,  
                        retryPIntent);  
  
                // Next retry should wait longer.  
                backoffTimeMs *= 2;  
                C2DMHelper.setBackoff(context, backoffTimeMs);  
            }  
        } else {  
            try {  
                onRegistered(context, registrationId);  
                C2DMHelper.setRegistrationId(context, registrationId);  
            } catch (IOException ex) {  
                Log.e(TAG, "Registration error " + ex.getMessage());  
            }  
        }  
    }  
}  